﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SCG.General
{
    public class Confluxer
    {
        public Confluxer()
        {
            MaxLength = 15;
        }
        public Confluxer(IEnumerable<string> lines)
        {
            MaxLength = 15;
            foreach (string line in lines)
            {
                if (line.Trim() == "")
                    continue;
                string[] seeds = line.Split(',', '\t');
                foreach (string seed in seeds)
                {
                    string trimmed = seed.Trim();
                    if (trimmed != "")
                        AddSeed(trimmed);
                }
            }
        }

        //max desired length
        public int MaxLength { get; set; }

        //Add a seed name
        public void AddSeed(string s)
        {
            _seeds.Add(s.ToLower());
        }
        public IList<string> Seeds
        {
            get
            {
                return _seeds.AsReadOnly();
            }
        }

        //Build the chains
        public void BuildChains()
        {
            if (_seeds.Count == 0)
                return;
            _chains.Clear();         
            foreach (string seed in _seeds)
            {
                if (seed.Length > 3)
                {
                    for (int n = 0; n < seed.Length - 2; n++)
                    {
                        string pair = seed.Substring(n, 3);
                        if (!_chains.ContainsKey(pair))
                        {
                            RandomList<char> letters = new RandomList<char>();
                            _chains[pair] = letters;
                        }
                        List<char> l = _chains[pair];
                        if (n + 3 >= seed.Length)
                            l.Add('*');
                        else
                            l.Add(seed[n + 3]);
                    }
                }
            }
        }

        //Return a random name
        public string RandomName
        {
            get
            {
                if (_chains.Count == 0)
                    BuildChains();
                if (_chains.Count == 0)
                    return "No Samples";
                string name;
                do
                {
                    name = GenerateName();
                }
                while (_namesUsed.Contains(name) || name.Length < 3);
                _namesUsed.Add(name);
                return name;
            }            
        }

        //reset
        public void Reset()
        {
            _namesUsed.Clear();
        }

        //private members
        private RandomList<String> _seeds = new RandomList<string>();    
        private Dictionary<string, RandomList<char>> _chains = new Dictionary<string, RandomList<char>>();
        private List<string> _namesUsed = new List<string>();

        //generate the name
        private string GenerateName()
        {
            string s = _seeds.RandomValue.Substring(0, 3);
            do
            {
                string pair = s.Substring(s.Length - 3, 3);
                if (!_chains.ContainsKey(pair))
                    break;
                RandomList<char> choices = _chains[pair];
                char c = choices.RandomValue;
                if (c != '*')
                    s += c;
                if (c == '*')
                    break;
            }
            while (s.Length < MaxLength);
            string[] parts = s.Split(' ');
            s = "";
            foreach (string part in parts)
            {
                if (part != "")
                {
                    if (s != "")
                        s += " ";
                    string proper = part.ToLower();
                    proper = proper.Substring(0, 1).ToUpper() + proper.Substring(1);
                    s += proper;
                }
            }
            return s.Trim();
        }
    }
}
